namespace :db do
  namespace :migrate do
    desc 'Reverts, renames and re-executes uncommitted migrations that conflict with already committed migrations'
    task :renumber => :environment do
      uncommitted = `svn status`.select {|line| line =~ /db\/migrate\//}.collect {|line| line.match(/ db\/migrate\/(.*rb)/)[1]}
      committed   = Dir.glob('db/migrate/*').collect {|line| line.match(/db\/migrate\/(.*rb)/)[1]} - uncommitted
    
      highest_committed   = committed.collect(&:to_i).max
      lowest_uncommitted  = uncommitted.collect(&:to_i).min
    
      schema_version = ActiveRecord::Base.connection.select_one("SELECT version FROM schema_info")["version"].to_i
    
      # revert uncommitted migrations
      uncommitted.sort_by(&:to_i).reverse.each do |migration|
        version = migration.to_i
        if version <= schema_version
          name = migration.match(/(\d*_.*).rb/)[1]
          class_name = (require 'db/migrate/' + name)[0]
          puts class_name.constantize.down 
        end
      end
    
      # set it back to the version prior to all the uncommitted migrations - this doesn't get done automatically by calling down
      ActiveRecord::Base.connection.execute("UPDATE schema_info SET version = #{schema_version - uncommitted.size}")
    
      version_offset = (highest_committed - lowest_uncommitted) + 1
    
      uncommitted.each do |old_name|
        version  = old_name.to_i + version_offset
        new_name = version.to_s.rjust(3,'0') + old_name.gsub(/\d/, '')
        `mv db/migrate/#{old_name} db/migrate/#{new_name}`
      end
    
      Rake::Task['db:migrate'].invoke
    end
  end
end